package com.ferryc.commons.shiro;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.ferryc.constant.GlobalConstant;
import com.ferryc.modules.sys.entity.SysUser;
import com.ferryc.modules.sys.service.ISysRoleService;
import com.ferryc.modules.sys.service.ISysUserService;
import com.ferryc.modules.sys.util.UserUtils;

/**
 * 
 * <pre>
 * 【类型】: ShiroDbRealm <br/> 
 * 【作用】: shiro权限认证. <br/>  
 * 【时间】：2017年5月23日 上午9:52:24 <br/> 
 * 【作者】：Ferry Chen <br/>
 * </pre>
 */
public class ShiroDbRealm extends AuthorizingRealm {
	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());
	public final static String REALM_NAME = "ShiroRealm";
	/** */
	@Autowired
	private ISysUserService sysUserService;
	/** */
	@Autowired
	private ISysRoleService sysRoleService;

	public ShiroDbRealm() {
		setName(REALM_NAME);
	}

	/**
	 * 
	 * 【方法名】 : (这里用一句话描述这个方法的作用). <br/>
	 * 【作者】: Ferry Chen .<br/>
	 * 【时间】： 2017年5月23日 上午9:52:52 .<br/>
	 * 【参数】： .<br/>
	 * 
	 * @param cacheManager
	 * @param matcher
	 *            .<br/>
	 */
	public ShiroDbRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
		super(cacheManager, matcher);
	}

	/**
	 * 获取权限授权信息，如果缓存中存在，则直接从缓存中获取，否则就重新获取， 登录成功后调用
	 */
	protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
		if (principals == null) {
			return null;
		}

		AuthorizationInfo info = null;

		info = (AuthorizationInfo) UserUtils.getCache(UserUtils.CACHE_AUTH_INFO);

		if (info == null) {
			info = doGetAuthorizationInfo(principals);
			if (info != null) {
				UserUtils.putCache(UserUtils.CACHE_AUTH_INFO, info);
			}
		}

		return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {

		logger.info("Shiro开始登录认证");
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		SysUser user = new SysUser();
		user.setLoginName(token.getUsername());
		user.setStatus(GlobalConstant.YES);
		List<SysUser> list = sysUserService.listByEntity(user);
		// 账号不存在
		if (CollectionUtils.isEmpty(list)) {
			return null;
		}
		SysUser loginUser = list.get(0);
		// 账号未启用
		if (loginUser.getStatus() == GlobalConstant.NO) {
			return null;
		}

		// 认证缓存信息
		return new SimpleAuthenticationInfo(loginUser, loginUser.getPassword().toCharArray(), ByteSource.Util.bytes(loginUser.getSalt()), getName());

	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		doClearCache(principals);
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 读取用户的权限和角色
		Set<String> roleSet = new HashSet<String>();
		String role = UserUtils.getUser().getRole();
		roleSet.add(role);

		info.setRoles(roleSet);
		List<String> userRermList = sysRoleService.getPermByRole(UserUtils.getUser().getRole());
		info.addStringPermissions(userRermList);
		return info;
	}

	// 清除缓存
	public void clearUserAuth() {
		PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
		doClearCache(principals);
	}

	public void clearAuthz() {
		this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
	}

	/*
	 * public void clearUserAuth() { logger.info("清除用户权限"); Cache cache =
	 * super.getAuthenticationCache();
	 * 
	 * // "authorizationCache" SimplePrincipalCollection principals = new
	 * SimplePrincipalCollection(); if (cache != null) { for (Object key :
	 * cache.keys()) { cache.remove(key); } }
	 * 
	 * }
	 */
}
